/**
 * Project: complex.cache
 * 
 * File Created at 2011-3-11
 * $Id: MemcachedClient.java 131 2011-03-20 11:35:31Z ymkyve501@163.com $
 * 
 * Copyright 1999-2100 Alibaba.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Alibaba Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Alibaba.com.
 */
package com.complex.memcachedClient;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 简单的MemcachedClient
 * 
 * @author gaoliang
 * @date 2011-3-11
 */
public class MemcachedClient {

	public static void main(String[] args) {
		MemcachedClient client = new MemcachedClient(new String[] {
				"127.0.0.1:11211", "127.0.0.1:12000" });
		client.add("aa", "aa");
		System.out.println(client.get("aa"));
		client.set("aa", "bb");
		System.out.println(client.get("aa"));
		client.replace("aa", "cc");
		System.out.println(client.get("aa"));
		client.delete("aa");
		System.out.println(client.get("aa"));
	}

	private Map<String, Socket> socketMap = new HashMap<String, Socket>();
	private List<String> hosts = new ArrayList<String>();
	private int num = 0; // 服务器数量

	public MemcachedClient(String[] servers) {
		init(servers);// 初始化并创建socket连接
	}

	public boolean add(String key, Object obj) {
		return Boolean.valueOf(write("add", key, obj, null));
	}

	public boolean add(String key, Object obj, Date date) {
		return Boolean.valueOf(write("add", key, obj, date));
	}

	public Object get(String key) {
		return write("get", key, null, null);
	}

	public boolean delete(String key) {
		return Boolean.valueOf(write("delete", key, null, null));

	}

	public boolean replace(String key, Object obj) {
		return Boolean.valueOf(write("replace", key, obj, null));
	}

	public boolean set(String key, Object obj) {
		return Boolean.valueOf(write("set", key, obj, null));
	}

	public Map<String,Object> getMulti(String[] keys){
		//省略100字
		//拼接get a b c
		//对返回的value做判断
		return null;
	}
	
	// 初始化并创建socket连接
	private void init(String[] servers) {
		try {
			for (String server : servers) {
				if (server.contains(":")) {
					String[] strs = server.split(":");
					socketMap.put(strs[0], new Socket(strs[0], Integer
							.valueOf(strs[1])));
					hosts.add(strs[0]);
					num++;
				}
			}
		} catch (Exception e) {
			System.out.println("init error");
		}
	}

	// 按hash取server的socket连接
	private Socket getSocket(String key) {
		int t = key.hashCode() % num;
		return socketMap.get(hosts.get(t));
	}

	// 向server发送命令,并返回结果
	private String write(String cmd, String key, Object obj, Date date) {
		byte[] value = null;
		if (obj != null) {
			value = obj.toString().getBytes();
		}
		
		//命令字符串
		String cmdStr = "";
		if ("add".equals(cmd) || "set".equals(cmd) || "replace".equals(cmd)) {
			cmdStr = String.format("%s %s %d %d %d\r\n", cmd, key, 32,
					date != null ? date.getTime() / 1000 : 0, value.length);
		}
		if ("get".equals(cmd)) {
			cmdStr = String.format("%s %s\r\n", cmd, key);
		}
		if ("delete".equals(cmd)) {
			cmdStr = String.format("%s %s\r\n", cmd, key);
		}
		Socket socket = getSocket(key);
		return getResponse(cmd, obj, cmdStr, socket);
	}

	//从数据器读取数据
	private String getResponse(String cmd, Object obj, String cmdStr,
			Socket socket) {

		try {
			BufferedOutputStream out = new BufferedOutputStream(socket
					.getOutputStream());
			DataInputStream in = new DataInputStream(socket.getInputStream());
			out.write(cmdStr.getBytes());
			if (obj != null) {
				out.write(obj.toString().getBytes());
				out.write("\r\n".getBytes());
			}
			out.flush();

			String response = readLine(in);
			if (("add".equals(cmd) || "set".equals(cmd) || "replace"
					.equals(cmd))
					&& "STORED".equals(response)) {
				return "TRUE";
			}
			if (("get".equals(cmd))) {
				if (response.contains("VALUE")) {
					String str = readLine(in);
					readLine(in);
					return str;
				} else {
					return null;
				}
			}
			if (("delete".equals(cmd)) && "DELETED".equals(response)) {
				return "TRUE";
			}
		} catch (Exception e) {
			System.out.println("write error");
			return "FALSE";
		}
		return "FALSE";
	}

	public String readLine(DataInputStream in) throws IOException {

		byte[] b = new byte[1];
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		boolean eol = false;

		while (in.read(b, 0, 1) != -1) {
			if (b[0] == 13) {
				eol = true;
			} else {
				if (eol) {
					if (b[0] == 10)
						break;

					eol = false;
				}
			}
			bos.write(b, 0, 1);
		}

		return bos.toString().trim();
	}
}
